/**
 * 
 */
package com.google.code.jkippt.http.paging;

import java.util.Iterator;

import com.google.code.jkippt.http.APIClient;
import com.google.code.jkippt.http.CommunicationException;
import com.google.code.jkippt.http.ResourceEndpointUrlFactory;
import com.google.code.jkippt.http.ServerErrorException;
import com.google.code.jkippt.parser.PageParser;
import com.google.code.jkippt.parser.PageParserBuilder;
import com.google.code.jkippt.parser.ParserException;

/**
 * Iterator over result pages.
 * @author Federico De Faveri defaveri@gmail.com
 */
public class PageIterator<T> implements Iterator<Page<T>> {

	protected APIClient client;
	protected String nextPageEndpoint;
	protected PageParserBuilder<T> parserBuilder;


	/**
	 * @param client the api client.
	 * @param parserBuilder the page parser builder.
	 * @param firstPageEndpoint the first page endpoint.
	 */
	public PageIterator(APIClient client, PageParserBuilder<T> parserBuilder, String firstPageEndpoint) {
		this.client = client;
		this.parserBuilder = parserBuilder;
		this.nextPageEndpoint = firstPageEndpoint;
	}

	/**
	 * {@inheritDoc}
	 */
	public boolean hasNext() {
		return nextPageEndpoint!=null;
	}

	/**
	 * {@inheritDoc}
	 */
	public Page<T> next() {
		if (!hasNext()) throw new IllegalStateException("There are no more pages");
		return getNextPage();
	}

	protected Page<T> getNextPage()
	{
		try {
			Page<T> nextPage = getPage(nextPageEndpoint);
			Meta meta = nextPage.getMeta();
			String nextEndPoint = meta.getNext();
			nextPageEndpoint = (nextEndPoint!=null)?ResourceEndpointUrlFactory.getNextPageEndpointUrl(nextEndPoint):null;

			return nextPage;
		} catch (Exception e) {
			throw new RuntimeException("An error occurred getting the next page", e);
		}
	}

	protected Page<T> getPage(String endpoint) throws ServerErrorException, CommunicationException, ParserException
	{
		String json = client.get(endpoint);
		PageParser<T> parser = parserBuilder.getParser(json);
		return new Page<T>(parser);
	}


	/**
	 * {@inheritDoc}
	 */
	public void remove() {
		throw new UnsupportedOperationException();	
	}

}
